package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
	"sync"
)

func main() {
	end := make(chan  bool)
	pool := NewTaskPool(2  , func(dt interface{}) {
		t , _ := dt.(*News)
		err := ioutil.WriteFile("./data/"+t.page + ".html" , t.body , 0666)
		fmt.Println(err)
	})
	go pool.Run()

	for i := 1; i < 20 ; i++  {
		go pool.addTask( &DownTask{page: strconv.Itoa(i)} )
	}

	pool.wait()
	
	<-end
}

type News struct {
	body []byte
	page string
}
type DownTask struct  {
	page string
	done bool
}

func (this *DownTask)IsDone() bool  {
	return  this.done
}

func (this *DownTask) Run (rsChan chan *taskResult)  {
	fmt.Println("down load run")
	news , err := downLoad163News(this.page)

	this.done = true

	if err != nil {
		fmt.Println(err)
	}

	t := &taskResult{data:&News{body:news,page:this.page}}
	rsChan<-t
}




func downLoad163News(n string) ([]byte , error) {
	res , err := http.Get("http://roll.mil.news.sina.com.cn/col/zgjq/index_"+n+".shtml")
	if   err == nil {
		defer res.Body.Close()
		return  ioutil.ReadAll(res.Body)
	}
	return nil , err
}





type taskHander func(chan bool , TaskInterface , chan *taskResult)
type taskEndHandler func(interface{})

type TaskPool struct {
	l *sync.Mutex
	max int
	pool chan bool
	trans chan *taskResult
	tasks chan TaskInterface
	allTask map[TaskInterface] bool
	taskEnd func(interface{})
}

func NewTaskPool(max int  ,taskEnd taskEndHandler) *TaskPool {

	return &TaskPool{
		max:max,
		l:new(sync.Mutex),
		pool:make(chan bool , max) ,
		tasks:make(chan TaskInterface , 1024),
		allTask:make(map[TaskInterface] bool , 1024) ,
		trans:make(chan *taskResult , 2 * max) ,
		taskEnd:taskEnd,
	}
}

func (this *TaskPool) Run()  {
	go func() {
		for ; ;  {
			r := <- this.trans
			this.taskEnd(r.data)
		}
	}()

	for ; ;  {
		b := false
		this.pool<-b
		go this.Task()
	}
}


func (this *TaskPool)Task()  {
	defer func() {
		<-this.pool
	}()
	//this.task.Run(this.trans)
	t := <-this.tasks
	t.Run(this.trans)
}

func (this *TaskPool) addTask( task TaskInterface )  {
	this.tasks<-task
	this.l.Lock()
	this.allTask[task] = false
	this.l.Unlock()
}

func (this *TaskPool) wait()  {
	timer := time.NewTicker(time.Second)
	for ; ;  {
		select {
			case <-timer.C :

				allDone := true
				for t , _ := range this.allTask {
					if t.IsDone() == false {
						allDone = false
						break
					}
				}
				if allDone {
					return
				}
		}
	}
}


type taskResult struct {
	data interface{}
}
type TaskInterface interface  {
	Run(chan *taskResult)
	IsDone() bool
}





